package com.shadowtorcher.soulknife;
/*
 * Copyright (C)  li, Shadow Torcher project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import com.shadowtorcher.soulknife.crud.Deleter;
import com.shadowtorcher.soulknife.crud.Querier;
import com.shadowtorcher.soulknife.crud.Updater;
import com.shadowtorcher.soulknife.exception.BeanConfigErrorException;
import com.shadowtorcher.soulknife.tableManager.Manager;
import com.shadowtorcher.soulknife.tableManager.SQLManager;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class SoulKnifeDB {

    public static PreparedQuerySoulKnifeDB runRawSQLQuery(String sql, Object... objects) {
        PreparedQuerySoulKnifeDB preparedQuerySoulKnifeDB = new PreparedQuerySoulKnifeDB();
        preparedQuerySoulKnifeDB.sql = sql;
        preparedQuerySoulKnifeDB.objects = objects;
        preparedQuerySoulKnifeDB.method = "raw";
        return preparedQuerySoulKnifeDB;
    }

    public static PreparedSoulKnifeDB runRawSQL(String sql, Object... objects) {
        PreparedSoulKnifeDB preparedSoulKnifeDB = new PreparedSoulKnifeDB();
        preparedSoulKnifeDB.sql = sql;
        preparedSoulKnifeDB.objects = objects;
        preparedSoulKnifeDB.method = "raw";
        return preparedSoulKnifeDB;
    }

    public static PreparedQuerySoulKnifeDB selectAll() {
        PreparedQuerySoulKnifeDB preparedSoulKnifeDB = new PreparedQuerySoulKnifeDB();
        preparedSoulKnifeDB.isAll = true;
        preparedSoulKnifeDB.method = "select";
        return preparedSoulKnifeDB;
    }

    public static PreparedQuerySoulKnifeDB selectWhere(String sql, Object... objects) {
        PreparedQuerySoulKnifeDB preparedSoulKnifeDB = new PreparedQuerySoulKnifeDB();
        preparedSoulKnifeDB.isAll = false;
        preparedSoulKnifeDB.sql = sql;
        preparedSoulKnifeDB.objects = objects;
        preparedSoulKnifeDB.method = "select";
        return preparedSoulKnifeDB;
    }

    public static PreparedSoulKnifeDB deletWhere(String sql, Object... objects) {
        PreparedSoulKnifeDB preparedSoulKnifeDB = new PreparedSoulKnifeDB();
        preparedSoulKnifeDB.sql = sql;
        preparedSoulKnifeDB.objects = objects;
        preparedSoulKnifeDB.method = "delete";
        return preparedSoulKnifeDB;
    }

    public static PreparedSoulKnifeDB updateWhere(DataSupport templateData, String sql, Object... objects) {
        PreparedSoulKnifeDB preparedSoulKnifeDB = new PreparedSoulKnifeDB();
        preparedSoulKnifeDB.sql = sql;
        preparedSoulKnifeDB.objects = objects;
        preparedSoulKnifeDB.method = "update";
        preparedSoulKnifeDB.templateData = templateData;
        return preparedSoulKnifeDB;
    }

    public static PreparedSoulKnifeDB insert(DataSupport data) {
        PreparedSoulKnifeDB preparedSoulKnifeDB = new PreparedSoulKnifeDB();
        preparedSoulKnifeDB.method = "insert";
        preparedSoulKnifeDB.templateData = data;
        return preparedSoulKnifeDB;
    }

    public static PreparedSoulKnifeDB drop() {
        PreparedSoulKnifeDB preparedSoulKnifeDB = new PreparedSoulKnifeDB();
        preparedSoulKnifeDB.method = "drop";
        return preparedSoulKnifeDB;
    }

    public static class PreparedQuerySoulKnifeDB {
        private boolean isAll;
        private String sql;
        private Object[] objects;
        private String method;

        public <T extends DataSupport> List<T> setClass(Class<T> object) throws SQLException, BeanConfigErrorException {
            switch (method) {
                case "select": {
                    List<T> list = new ArrayList<>();
                    ResultSet resultSet;
                    if (isAll) {
                        resultSet = Querier.doQuery(object.getSimpleName(), null);
                    } else {
                        resultSet = Querier.doQuery(object.getSimpleName(), sql, objects);
                    }
                    while (resultSet.next()) {
                        @SuppressWarnings("unchecked")
                        T t = (T) DataSupport.getInstance(resultSet, object);
                        list.add(t);
                    }
                    return list;
                }
                case "raw": {
                    List<T> list = new ArrayList<>();
                    ResultSet resultSet = SQLManager.runQuery(sql, objects);
                    while (resultSet.next()) {
                        @SuppressWarnings("unchecked")
                        T t = (T) DataSupport.getInstance(resultSet, object);
                        list.add(t);
                    }
                    return list;
                }
                default: {
                    return new ArrayList<>();
                }
            }
        }
    }

    public static class PreparedSoulKnifeDB {
        private DataSupport templateData;
        private String sql;
        private Object[] objects;
        private String method;

        public boolean setClass(Class<? extends DataSupport> object) throws SQLException, BeanConfigErrorException {
            switch (method) {
                case "delete":
                    return Deleter.doDelete(object.getSimpleName(), sql, objects);
                case "update":
                    return Updater.doUpdate(object.getSimpleName(), templateData, sql, objects);
                case "insert":
                    templateData.save();
                    return true;
                case "raw":
                    return SQLManager.runSQL(sql, object);
                case "drop": {
                    Manager.Inited.remove(object.getSimpleName());
                    return SQLManager.runSQL("drop table " + object.getSimpleName());
                }
                default:
                    return false;
            }
        }
    }

}
